// ==UserScript==
// @name         百度网盘共享文件库目录清单导出
// @namespace    https://github.com/Avens666/BaidunNetDisk-script
// @version      0.5
// @description  try to take over the world!
// @author       Avens
// @match        https://pan.baidu.com/mbox*
// @grant        none
// @require      https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.3/FileSaver.min.js
// @require      https://cdn.bootcdn.net/ajax/libs/jquery/3.1.1/jquery.min.js
// @note         2020.10.26-V0.5 增加取子目录的功能
// ==/UserScript==

//
// 主目录类型 type1 <li class="" node-type="sharelist-item" data-id="94956815229992845" data-frm="2687769004" data-to="2181389256" data-fid="1117071517154765">
// 主目录类型 type2 <li class="" node-type="sharelist-item" data-id="8522742650637316248" data-frm="574440818" data-gid="697250947953272568" data-fid="494436556508384">
// 子目录 <li class="" node-type="sharelist-item" data-fid="715901954634145">

(function () {
    'use strict';
    var classMap = {
        'title': 'sharelist-view-toggle',
    };
    var g_type = 0;
    var g_gid;
    var g_msgid;
    var g_frm;
    var g_to_uk;

    function getGID() {
        let lst = Array.from(document.getElementsByTagName('li')).filter(item => item.getAttribute('node-type') === 'sharelist-item');
        let obj = lst.filter(item => item.getAttribute('class') === 'on');
        let obj_length = obj.length;
        g_msgid = null;
        if (obj_length != 1) {
            alert("请在文件库根目录下,仅选中一个目录后执行!");
            return;
        }

        let lt = Array.from(obj[0].children).filter(item => item.getAttribute('class') === 'sharelist-item-size global-ellipsis');
        if (lt.length == 1) {
            if (lt[0].textContent == '-') {
                g_msgid = obj[0].getAttribute('data-id');
                g_gid = obj[0].getAttribute("data-gid");
                g_frm = obj[0].getAttribute("data-frm");
                g_to_uk = obj[0].getAttribute('data-to');

                if (g_to_uk === null) {
                    g_type = 2;
                } else {
                    g_type = 1;
                }
            }
        } else {
            alert("请在文件库根目录下,仅选中一个目录后执行!");
            return;
        }

        if (g_msgid === null) {
            alert("请在文件库根目录下,选中一个目录后执行!");
        } else {
            alert("取得主目录信息成功，可以单独导出该目录下的子目录信息!");
        }
    }

    function exportSubDir() {
        let lst = Array.from(document.getElementsByTagName('li')).filter(item => item.getAttribute('node-type') === 'sharelist-item');
        let obj = lst.filter(item => item.getAttribute('class') === 'on');
        let obj_length = obj.length;
        let dirinfo = [];

        if (g_msgid === null) {
            alert("请在文件库根目录下执行“获取ID”!");
            return;
        }

        for (let i = 0; i < obj_length; i++) {
            let _name = $(obj[i]).find('span[class="global-ellipsis sharelist-item-title-name"]').find('a').html();
            let _size = 1;
            let _isDir = 1;
            let _fs_id = obj[i].getAttribute("data-fid");
            let dinfo = createFileInfo(_name, _isDir, _size, _fs_id, g_msgid, g_frm, g_to_uk);
            dirinfo.push(dinfo);
        }

        for (let n = 0; n < dirinfo.length; n++) {
            queryDir(dirinfo[n], "", 0);
            send("\r\n");
        }

        send("<end>");
    }

    function exportDir() {
        let lst = Array.from(document.getElementsByTagName('li')).filter(item => item.getAttribute('node-type') === 'sharelist-item');
        let obj = lst.filter(item => item.getAttribute('class') === 'on');
        let obj_length = obj.length;
        let dirinfo = []; //一级列表数组
        g_msgid = null;
        for (let i = 0; i < obj_length; i++) {
            let lt = Array.from(obj[0].children).filter(item => item.getAttribute('class') === 'sharelist-item-size global-ellipsis');
            if (lt.length == 1) {
                if (lt[0].textContent == '-') //文件夹
                {
                    let _msgid = obj[i].getAttribute('data-id');
                    g_msgid = _msgid;
                    g_gid = obj[i].getAttribute("data-gid");
                    let _frm = obj[i].getAttribute("data-frm");
                    let _to_uk = obj[i].getAttribute('data-to');
                    let _fs_id = obj[i].getAttribute('data-fid');

                    if (_to_uk === null) {
                        g_type = 2;
                    } else {
                        g_type = 1;
                    }

                    let _name = $(obj[i]).find('span[class="global-ellipsis sharelist-item-title-name"]').find('a').html();
                    let _size = 1;
                    let _isDir = 1;
                    let dinfo = createFileInfo(_name, _isDir, _size, _fs_id, _msgid, _frm, _to_uk);
                    dirinfo.push(dinfo);
                }
            }
        }

        if (g_msgid === null) {
            alert("请在文件库根目录下执行!");
            return;
        }

        for (let n = 0; n < dirinfo.length; n++) {
            queryDir(dirinfo[n], "", 0);
            send("\r\n");
        }

        send("<end>");
    }

    function send(text) {
        let sendurl = "http://localhost:9090/txt?txt=" + encodeURIComponent(text);
        $.ajax({
            type: 'GET',
            url: sendurl,
            data: {},
            dataType: "json",
            async: false,
            success: function (res) {
            },
            error: function (err) {
            }
        });
    }

    function queryDir(dir_info, blank, level) {

        if (dir_info.isDir == 0) {
            send(blank + "│  " + dir_info.name + " (" + getSize(dir_info.size) + ")  --  " + dir_info.path + "\r\n");
            return;
        }

        level++;
        send(blank + "├─" + dir_info.name + " [文件夹" + "\r\n");

        let dir_url = "";

        let n_page = 1;
        let b_more = 1;

        let is_failed_p = 0;
        while (n_page <= 30 && b_more == 1 || is_failed_p > 0) {
            if (is_failed_p > 0) {
                console.log("is_failed_p:" + is_failed_p + " page: " + n_page + " dir_info.isDir: " + dir_info.isDir);
                if (is_failed_p > 2) {
                    break;
                }
            }

            if (g_type == 1) {
                dir_url = "https://pan.baidu.com/mbox/msg/shareinfo?msg_id=" + dir_info.msg_id + "&page=" + n_page + "&from_uk=" + dir_info.from_uk + "&to_uk=" + dir_info.to_uk + "&type=1&fs_id=" + dir_info.fs_id + "&num=100";
            } else if (g_type == 2) {
                dir_url = "https://pan.baidu.com/mbox/msg/shareinfo?msg_id=" + dir_info.msg_id + "&page=" + n_page + "&from_uk=" + dir_info.from_uk + "&gid=" + g_gid + "&type=2&fs_id=" + dir_info.fs_id + "&num=100";
            }

            $.ajax({
                type: 'GET',
                url: dir_url,
                data: {},
                dataType: "json",
                async: false,
                success: function (res) {
                    if (!res || res.errno != 0) {
                        console.warn("errno:" + res.errno + "url: " + dir_url);
                        is_failed_p++;
                        return;
                    }
                    is_failed_p = 0;
                    let file_lst = res.records;
                    let len = file_lst.length;
                    b_more = res.has_more;

                    for (let n = 0; n < len; n++) {
                        let _name = file_lst[n].server_filename;
                        let _size = file_lst[n].size;
                        let _isDir = file_lst[n].isdir;
                        let _fs_id = file_lst[n].fs_id;
                        let dinfo = createFileInfo(_name, _isDir, _size, _fs_id, dir_info.msg_id, dir_info.from_uk, dir_info.to_uk);
                        let lastn = file_lst[n].path.lastIndexOf("/");
                        if (lastn > 0)
                            dinfo.path = file_lst[n].path.substring(0, lastn + 1);
                        else
                            dinfo.path = file_lst[n].path;
                        send(level);
                        queryDir(dinfo, blank + "│  ", level)
                    }
                    n_page++;
                },
                error: function (err) {
                    console.error(err);
                    is_failed_p++;
                }
            });
        }
    }

    // 目录或文件对象
    function createFileInfo(name, isDir, size, fs_id, msg_id, frm, to) {
        let ofile = new Object;
        ofile.name = name;
        ofile.isDir = isDir;
        ofile.size = size;
        ofile.fs_id = fs_id;
        ofile.msg_id = msg_id;
        ofile.from_uk = frm;
        ofile.to_uk = to;
        ofile.path = "";
        return ofile;
    }

    function getSize(s) {
        if (s < 1024) {
            return s + " Byte";
        } else if (s > 1024 && s < 1048576) {
            return Math.round(s / 1024 * 100) / 100.00 + " KB";
        } else if (s > 1048576 && s < 1073741824) {
            return Math.round(s / (1048576) * 100) / 100.00 + " MB";
        } else {
            return Math.round(s / (1073741824) * 100) / 100.00 + " GB";
        }
    };

    //添加导出按钮
    function addButton() {
        let $dropdownbutton = $('<a class="list-filter" href="javascript:void( 0 );" onclick="exportDir()" node-type="btn_export" title="在文件库根目录，选择要导出的文件夹，点击按钮，清单生成后会提示保存文件。\n如果文件夹内部子文件夹很多，需要等待较长时间。8000个子文件夹大概1小时" style="display: inline;">导出目录</a>');
        $('.' + classMap['title']).append($dropdownbutton);
        $dropdownbutton.click(exportDir);

        let $dropdownbutton3 = $('<a class="list-filter" href="javascript:void( 0 );" onclick="exportSubDir()" node-type="btn_export" title="导出任意层级的子文件夹信息。\n需要先在主目录下，选择文件夹所在根目录，点击<ID按钮>获取主目录信息。\n然后可以进入子目录，选择要导出的子目录进行导出!" style="display: inline;">子目录</a>');
        $('.' + classMap['title']).append($dropdownbutton3);
        $dropdownbutton3.click(exportSubDir);

        let $dropdownbutton2 = $('<a class="list-filter" href="javascript:void( 0 );" onclick="getGID()" node-type="btn_export" title="为了导出子文件夹，需要先获取主目录信息。\n请在文件库根目录下，选择要导出的子目录所在的根目录后执行!" style="display: inline;">ID</a>');
        $('.' + classMap['title']).append($dropdownbutton2);
        $dropdownbutton2.click(getGID);
    }
    addButton();

})();